// Render Pass Group Queue
// (c) jimon game studio

#ifndef JEH_JERENDERPASSGROUPQUEUE
#define JEH_JERENDERPASSGROUPQUEUE

#include "ISceneManager.h"

namespace je
{
	namespace scene
	{
		//! Render Pass Group Queue
		class jeRenderPassGroupQueue
		{
		protected:
			//! Group Id
			RenderPassGroup CurrentGroup;

			//! Group Rights
			RenderPassGroupRights CurrentRights;

			struct QueueNodeObject
			{
				ISceneNode * Node;
				f32 Distance;

				QueueNodeObject(ISceneNode * NewNode)
					:Node(NewNode),Distance(0.0f)
				{
				}
			};

			//! Queue List Type
			typedef jeDynamicArray<QueueNodeObject*> QueueListType;

			//! Queue
			QueueListType Queue;
		public:
			//! Constructor
			jeRenderPassGroupQueue(RenderPassGroup Group,RenderPassGroupRights Rights)
				:CurrentGroup(Group)
			{
				SetRights(Rights);
			}

			//! Desturctor
			~jeRenderPassGroupQueue()
			{
				for(u32 i=0;i<Queue.GetSize();i++)
					JEDELETE(Queue[i])
				Queue.Clear();
			}

			//! Set Rights
			void SetRights(RenderPassGroupRights Rights)
			{
				CurrentRights = Rights;
				if(CurrentRights == RPTR_AUTO)
				{
					switch(CurrentGroup)
					{
					case RPG_SOLID:
						CurrentRights = RPTR_NONE;
						break;
					case RPG_TRANSPARENT:
						CurrentRights = RPTR_DESCENDING;
						break;
					default:
						CurrentRights = RPTR_NONE;
						break;
					}
				}
			}

			//! Return Current Group Id
			RenderPassGroup GetGroup()
			{
				return CurrentGroup;
			}

			//! Add Node
			void AddNode(ISceneNode * Node)
			{
				QueueNodeObject * QueueNode = NULL;
				JENEW(QueueNode,QueueNodeObject(Node))
				Queue.InsertElement(QueueNode);
			}

			//! Remove Node, return true if removed
			u1 RemoveNode(ISceneNode * Node)
			{
				for(u32 i=0;i<Queue.GetSize();i++)
					if(Queue[i]->Node == Node)
					{
						JEDELETE(Queue[i])
						Queue.EraseElement(i);
						return true;
					}
				return false;
			}

			//! Return Node Count
			u32 GetNodeCount()
			{
				return Queue.GetSize();
			}

			//! Sorting
			static u8 QueueSortEnableLayers(QueueNodeObject * Elem1,QueueNodeObject * Elem2)
			{
				return (Elem1->Node->GetLayer()>Elem2->Node->GetLayer())?1:((Elem1->Node->GetLayer()<Elem2->Node->GetLayer())?2:4);
			}

			//! Asc Sorting
			static u8 QueueSortAscEnableLayers(QueueNodeObject * Elem1,QueueNodeObject * Elem2)
			{
				return (Elem1->Node->GetLayer()>Elem2->Node->GetLayer())?1:((Elem1->Node->GetLayer()<Elem2->Node->GetLayer())?2:((Elem1->Distance>Elem2->Distance)?1:((Elem1->Distance<Elem2->Distance)?2:4)));
			}

			//! Asc Sorting
			static u8 QueueSortAscDisableLayers(QueueNodeObject * Elem1,QueueNodeObject * Elem2)
			{
				return (Elem1->Distance>Elem2->Distance)?1:((Elem1->Distance<Elem2->Distance)?2:4);
			}

			//! Desc Sorting
			static u8 QueueSortDescEnableLayers(QueueNodeObject * Elem1,QueueNodeObject * Elem2)
			{
				return (Elem1->Node->GetLayer()>Elem2->Node->GetLayer())?1:((Elem1->Node->GetLayer()<Elem2->Node->GetLayer())?2:((Elem1->Distance<Elem2->Distance)?1:((Elem1->Distance>Elem2->Distance)?2:4)));
			}

			//! Desc Sorting
			static u8 QueueSortDescDisableLayers(QueueNodeObject * Elem1,QueueNodeObject * Elem2)
			{
				return (Elem1->Distance<Elem2->Distance)?1:((Elem1->Distance>Elem2->Distance)?2:4);
			}

			//! Sort Nodes
			void Sort(ICameraSceneNode * CurrentCamera,u1 EnableLayers)
			{
				if((CurrentRights == RPTR_NONE) && (!EnableLayers))
					return;
				
				u1 NeedResort = false;
				
				if(CurrentRights != RPTR_NONE)
					for(u32 i=0;i<Queue.GetSize();i++)
					{
						f32 NewDistance = (Queue[i]->Node->GetPosition() - CurrentCamera->GetPosition()).GetDistanceQR();
						if(Queue[i]->Distance != NewDistance)
						{
							Queue[i]->Distance = NewDistance;
							NeedResort = true;
						}
					}

				if(EnableLayers && (!NeedResort))
					for(u32 i=1;i<Queue.GetSize();i++)
						if((Queue[i-1]->Node->GetLayer() > Queue[i]->Node->GetLayer()))
						{
							NeedResort = true;
							break;
						}

				if(NeedResort)
					Queue.ShellSort(CurrentRights == RPTR_NONE ? QueueSortEnableLayers : (CurrentRights == RPTR_ASCENDING ? (EnableLayers ? QueueSortAscEnableLayers : QueueSortAscDisableLayers) : (EnableLayers ? QueueSortDescEnableLayers : QueueSortDescDisableLayers)));

			}

			//! Render Nodes
			void OnRender()
			{
				for(u32 i=0;i<Queue.GetSize();i++)
					if(Queue[i]->Node->IsInFrame())
						Queue[i]->Node->OnRender();
			}

			//! Render Node
			void OnRender(u32 NodeIndex)
			{
				if(Queue[NodeIndex]->Node->IsInFrame())
					Queue[NodeIndex]->Node->OnRender();
			}
		};
	}
}

#endif
